home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 June / MacFormat 25.iso / Shareware City / HyperCard / Pictoids 2.0 / BitMapToRegion ƒ / BitMapRgn.c next >
Encoding:
C/C++ Source or Header  |  1990-12-01  |  9.9 KB  |  329 lines  |  [TEXT/KAHL]

  1. /*
  2. >>    BitMapRgn.c, June 90                                                <<
  3. >>                                                                        <<
  4. >>  Nigel Perry, np@doc.ic.ac.uk                                        <<
  5. >>  Dept of Computing, Imperial College, 180 Queens Gate,               <<
  6. >>  London SW7 2BZ, England                                             <<
  7. >>                                                                        <<
  8. >>    Version of the BitMapRgn trap (0xA8D7) which is not in all systems  <<
  9. >>  This C/asm version is an extension of a C routine written           <<
  10. >>    by Juri Munkki in April 89. Added error checks, now works with a    <<
  11. >>  BitMap with any origin, used assembler for speed                    <<
  12. >>                                                                         <<
  13. >>    Juri Munkki, jmunkki@kampi.hut.fi                                    <<
  14. >>    Helsinki University of Technology Computing Centre                    <<
  15. >>    Otakaari 1 U044B, SF02150 Espoo, Finland                            <<
  16. >>                                                                        <<
  17. >>    This program is in the PUBLIC DOMAIN.                                <<
  18. */
  19.  
  20. /* Define TRAPATCH if trap patch version (project BMTR Trap π).
  21.    Will compile a TRAP resource and write it to BMTR XCMD π.rsrc,
  22.    to use in the BMTR Patcher.π & BMTR Init.π this TRAP resource must be
  23.    copied with ResEdit to the appropriate π.rsrc file. DO NOT change this
  24.    project to write directly to another π.rsrc file, they contain other
  25.    resources which you will DESTROY.
  26.  */
  27. #define TRAPATCH
  28.  
  29. #include <asm.h>
  30. #define _BitMapToRegion                 0xA8D7
  31. #define _Unimplemented                    0xA89F
  32.  
  33. #define rgnTooBigErr -500
  34.  
  35. #ifdef TRAPATCH
  36. #define BitMapRgn main
  37. /* CODE header */
  38. header()
  39. {    extern pascal OSErr BitMapRgn();
  40.  
  41.     asm
  42.     {    bra.s    @1                ; header
  43.         dc.b    'n','p','9','0'    ; header + 2
  44.         dc.b    'j','u','r','i'    ; header + 6
  45.     @1:    jmp        BitMapRgn
  46.     }
  47. }
  48. #endif TRAPATCH
  49.  
  50. /*
  51. >>    Convert a bitmap into a region.
  52. */
  53. pascal OSErr BitMapRgn(RgnHandle, BitMap *);
  54. pascal OSErr BitMapRgn(Target, Bits)
  55. RgnHandle    Target;
  56. BitMap        *Bits;
  57. {    int                *TargetBase;        /* StripAddress(*Target) */
  58.     int                *RowStart;            /* Index of first x value on row */
  59.     int                TargetSize,RgnSize;    /* Size in data words & bytes */
  60.     Rect            TempRect,RgnBounds;    /* Temporary & region bounds rects */
  61.     BitMap            RowBitMap;            /* Working bitmap with one row in it */
  62.     int                i;                    /* Row counter in a "for" loop */
  63.     int                diff;
  64.     int                left;
  65.     /* three address registers a2-4 */
  66.     register int    *TargetP;            /* Pointer to region data array */
  67.     register int    *MaxTarget;            /* Memory management stuff */
  68. #ifndef TRAPATCH
  69.     register long    *BitP;                /* Pointer to current line */
  70. #else
  71.     /* need to force a4 in LSC CODE resource */
  72. #define BitP a4
  73. #endif
  74.     /* five data registers d3-7 */
  75.     register int    shiftcount;            /* shift count for BitWord */
  76.     register long    BitWord;            /* current 32 bits of line */
  77.     register int    x;                    /* Column counter in a "for" loop */
  78.     register int    pixelstatus;        /* Flag is false if last pixel is white */
  79.     register int    right;
  80.     
  81. #ifdef TRAPATCH
  82.     /* save a4 in patch */
  83.     asm
  84.     {    move.l    a4,-(a7)
  85.     }
  86. #endif
  87.     asm
  88.     {    move.l    #4096,d0        /* Initial guess for final region size */
  89.         move.w    d0,TargetSize
  90.         move.l    Target,a0        /* Allocate initial data buffer */
  91.         _SetHandleSize
  92.         bne        @bomb            /* Did we run out of RAM? 0=failure. */
  93.         _HLock                    /* HLock((Handle)Target); */
  94.     
  95.         /* TargetP points to region data */
  96.         move.l    Target,a0        /* TargetBase = StripAddres(*(Handle)Target) */
  97.         move.l    (a0),d0
  98.         _StripAddress
  99.         move.l    d0,a0
  100.         move.l    d0,TargetBase
  101.         lea        10(a0),TargetP    /* TargetP = (TargetBase + 10); */
  102.         /* A safe maximum value for our index */
  103.         move.w    TargetSize,d0
  104.         lea        -8(a0,d0.w),MaxTarget    /* MaxTarget = TargetBase + TargetSize - 8; */
  105.  
  106.         /*    Set region bounds to nothing: */
  107.         move.l    #0x7FFF7FFF,RgnBounds.top    /* SetRect(&RgnBounds,32767,32767,-32767,-32767); */
  108.         move.l    #0x80018001,RgnBounds.bottom
  109.     
  110.         /*    Set up a bitmap with a single line: */
  111.         move.l    Bits,a0
  112.         move.w    OFFSET(BitMap,bounds)+OFFSET(Rect,left)(a0),TempRect.left    /* Set up left & right bounds */
  113.         move.w    OFFSET(BitMap,bounds)+OFFSET(Rect,right)(a0),TempRect.right
  114.         move.w    OFFSET(BitMap,bounds)+OFFSET(Rect,top)(a0),d0
  115.         move.w    d0,TempRect.top;        /* Single row bitmap with height = 1 */
  116.         addq.w    #1,d0
  117.         move.w    d0,TempRect.bottom
  118.         move.l    TempRect.top,RowBitMap.bounds.top    /* RowBitMap.bounds=TempRect; */
  119.         move.l    TempRect.bottom,RowBitMap.bounds.bottom;
  120.         moveq    #15,d0                /* RowBitMap.rowBytes = ((TempRect.width + 15) >> 4) << 1; */
  121.         add.w    TempRect.right,d0
  122.         sub.w    TempRect.left,d0
  123.         asr.w    #4,d0
  124.         asl.w    #1,d0
  125.         move.w    d0,RowBitMap.rowBytes
  126.         ext.w    d0                    /* RowBitMap.baseAddr = NewPtr(RowBitMap.rowBytes); */
  127.         _NewPtr
  128.         bne        @bomb
  129.         move.l    a0,RowBitMap.baseAddr
  130.     }
  131.  
  132.     /*    Start out with the first line of the source bitmap */
  133.     CopyBits(Bits,&RowBitMap,&TempRect,&RowBitMap.bounds,srcCopy,0);
  134.     
  135.     asm
  136.     {    /* right = Bits->bounds.right; */
  137.         move.l    Bits,a0
  138.         move.w    OFFSET(BitMap,bounds)+OFFSET(Rect,right)(a0),right
  139.         move.w    OFFSET(BitMap,bounds)+OFFSET(Rect,left)(a0),left
  140.         /* i = Bits->bounds.bottom - Bits->bounds.top; */
  141.         move.w    OFFSET(BitMap,bounds)+OFFSET(Rect,bottom)(a0),d0
  142.         sub.w    OFFSET(BitMap,bounds)+OFFSET(Rect,top)(a0),d0
  143.         move.w    d0,i
  144.     }
  145.     
  146.     for(; i >= 0; i--)    /* For every line and more */
  147.     {    /*    Row data starts with Y value*/
  148.         asm
  149.         {    move.w    TempRect.top,(TargetP)+    /* *TargetP++ = TempRect.top; */
  150.         }
  151.         RowStart = TargetP;                    /* X values on row start here */
  152.         pixelstatus = 0;                    /* Pixels outside bitmap are white */
  153.         
  154.         asm
  155.         {    move.l    RowBitMap.baseAddr,BitP    /* BitP = (long *)RowBitMap.baseAddr; */
  156.         }
  157.         shiftcount = 0;
  158.         for(x = left; x<right; x++)
  159.         {    asm
  160.             {    tst.w    shiftcount
  161.                 bne.s    @nextBit
  162.                 moveq    #32,shiftcount
  163.                 move.l    (BitP)+,BitWord            /* BitWord = *BitP++; */
  164.             @nextBit
  165.                 subq.w    #1,shiftcount
  166.                 /* Test for a change */
  167.                 /* if((BitTst(RowBitMap.baseAddr,x)!=0) != pixelstatus) */
  168.                 lsl.l    #1,BitWord
  169.                 scs        d0
  170.                 eor.b    pixelstatus,d0
  171.                 beq        @elselab
  172.             }
  173.             {    asm
  174.                 {    /* Color changed */
  175.                     not.b    pixelstatus            /* pixelstatus = !pixelstatus; */
  176.                     /*    Record x coordinate    */
  177.                     move.w    x,(TargetP)+        /* *TargetP++ = x; */
  178.                 }
  179.                 if(TargetP >= MaxTarget)        /* Is the buffer full? */
  180.                 {    asm
  181.                     {    move.l    TargetP,d0        /* diff = TargetP - TargetBase; */
  182.                         sub.l    TargetBase,d0
  183.                         move.w    d0,diff
  184.                         add.w    #2048,TargetSize    /* Enlarge the buffer */ 
  185.                         bvc.s    @sizeOk                /* if((TargetSize+=2048) > 32767) */
  186.                         move.w    #rgnTooBigErr,d0
  187.                         bra        @bomb2
  188.                     @sizeOk
  189.                         move.l    Target,a0        /* Unlock to change size */
  190.                         _HUnlock
  191.                         move.w    TargetSize,d0    /* Change the size */
  192.                         ext.l    d0
  193.                         _SetHandleSize
  194.                         bne        @bomb2            /* No success? */
  195.                         _HLock                    /* Lock it again */
  196.                     
  197.                         move.l    Target,a0        /* TargetBase = StripAddress(*(Handle)Target); */
  198.                         move.l    (a0),d0
  199.                         _StripAddress
  200.                         move.l    d0,TargetBase
  201.                         move.l    d0,TargetP
  202.                         adda.w    diff,TargetP    /* TargetP = TargetBase + diff; */
  203.                         /* New maximum index */
  204.                         subq.l    #8,d0
  205.                         move.l    d0,MaxTarget    /* MaxTarget= TargetBase + TargetSize; */
  206.                         adda.w    TargetSize,MaxTarget
  207.                     }
  208.                 }
  209.             }
  210.         elselab:
  211.             ;
  212.         }
  213.         if(pixelstatus) /*    Last pixel was black, record edge    */
  214.             asm
  215.             {    move.w    x,(TargetP)+            /* *TargetP++=x; */
  216.             }
  217.         if(RowStart==TargetP)                    /*    Row was empty (no changes) */
  218.             TargetP--;                            /*    Remove Y value from data */
  219.         else
  220.         {    /*    Check for new region bounds: */
  221.             asm
  222.             {    move.l    RowStart,a0            /* if(*RowStart < RgnBounds.left) */
  223.                 move.w    (a0),d0
  224.                 cmp.w    RgnBounds.left,d0
  225.                 bge.s    @else1
  226.                 move.w    d0,RgnBounds.left    /* RgnBounds.left = *RowStart; */
  227.             @else1
  228.                 move.w    -2(TargetP),d0        /* if(TargetP[-1] > RgnBounds.right) */
  229.                 cmp.w    RgnBounds.right,d0
  230.                 ble.s    @else2
  231.                 move.w    d0,RgnBounds.right    /* RgnBounds.right = TargetP[-1]; */
  232.             @else2
  233.             }
  234.             
  235.             RgnBounds.bottom = TempRect.top;
  236.  
  237.             /* Write an "end of line" flag */
  238.             asm
  239.             {    move.w    #32767,(TargetP)+        /* *TargetP++ = 32767; */
  240.             }
  241.         }
  242.  
  243.         /*    Copy current line into the single line bitmap: */
  244.         if(i>0) CopyBits(Bits,&RowBitMap,&TempRect,&RowBitMap.bounds,srcCopy,0);
  245.  
  246.         TempRect.top++; TempRect.bottom++;            /*    Move one line down            */
  247.         
  248.         /*    If we are still inside the bitmap, XOR this line with the previous line:*/
  249.         if(i>1)    CopyBits(Bits,&RowBitMap,&TempRect,&RowBitMap.bounds,srcXor,0);
  250.     }
  251.  
  252.     /* RgnBounds.top = TargetBase[5]; */    /* Top boundary is first recorded Y coordinate */
  253.     asm
  254.     {    move.l    TargetBase,a0    ; (*)
  255.         move.w    10(a0),RgnBounds.top
  256.     }
  257.  
  258.     /*    If the region is empty, set the bounds rect to an empty rectangle: */
  259.     if(RgnBounds.right<=RgnBounds.left || RgnBounds.bottom<=RgnBounds.top)
  260.         asm
  261.         {    clr.l    RgnBounds.top        /* SetRect(&RgnBounds,0,0,0,0); */
  262.             clr.l    RgnBounds.bottom
  263.         }
  264.  
  265.     asm
  266.     {    /*    Write an "end of region" flag */
  267.         move.w    #32767,(TargetP)+        /* *TargetP++ = 32767; */
  268.     
  269.         /*    Calculate region size.*/
  270.         move.l    TargetP,d0        /* RgnSize = (TargetP - TargetBase) * 2; */
  271.         ; sub.l    TargetBase,d0    /* result must be <= 32767 */
  272.         sub.l    a0,d0    ; TargetBase is in a0 (*)
  273.         cmp.w    #28,d0            /* if(RgnSize<=28) RgnSize=10; */
  274.         bgt.s    @3
  275.         moveq    #10,d0            /* Rectangular or empty region is only a Rect */
  276.     @3:    move.w    d0,RgnSize    ; (**)
  277.     
  278.         /* Store region bounds rectangle */
  279.         /* ((RgnPtr)TargetBase)->rgnBBox=RgnBounds; */
  280.         ; move.l    TargetBase,a0 already in a0 (*)
  281.         move.l    RgnBounds.top,OFFSET(Region,rgnBBox)+OFFSET(Rect,top)(a0)
  282.         move.l    RgnBounds.bottom,OFFSET(Region,rgnBBox)+OFFSET(Rect,bottom)(a0)
  283.         /* Store region size (low 16 bits) */
  284.         /* ((RgnPtr)TargetBase)->rgnSize=RgnSize; */
  285.         move.w    d0,OFFSET(Region,rgnSize)(a0)    ; RgnSize is in d0 (**)
  286.     }
  287.     
  288.     
  289.  
  290.     asm
  291.     {    /*    Unlock our target region. */
  292.         move.l    Target,a0        /* HUnlock((Handle)Target);    */
  293.         _HUnlock
  294.         
  295.         /*    Resize region to optimally small */
  296.         move.w    RgnSize,d0
  297.         ext.l    d0
  298.         _SetHandleSize            /* SetHandleSize((Handle)Target,RgnSize); */
  299.         bne.s    @bomb2            /* shouldn't occur... */
  300.     }
  301.  
  302.     asm
  303.     {    move.l    RowBitMap.baseAddr,a0    /* DisposPtr(RowBitMap.baseAddr) */
  304.         _DisposPtr
  305.         bne.s    @bomb
  306.         bra.s    @done                    /* return noErr */
  307. bomb2:
  308.         move.w    d0,-(a7)
  309.         move.l    RowBitMap.baseAddr,a0
  310.         _DisposPtr
  311.         bra.s    @bomb3
  312. bomb:
  313.         move.w    d0,-(a7)
  314. bomb3:
  315.         move.l    Target,a0
  316.         move.l    a0,-(a7)
  317.         _HUnlock                        /* may still be locked */
  318.         _SetEmptyRgn
  319.         move.w    (a7)+,d0
  320.         
  321. done:
  322. #ifdef TRAPATCH
  323.         ; get a4 back
  324.         move.l    (a7)+,a4
  325. #endif
  326.  
  327.     }
  328.  
  329. }